﻿using System.Collections.Concurrent;
using UnityEngine;
using UnityEngine.Events;

namespace Jinndev {

    public class BaseBehaviour : MonoBehaviour {

        //public UnityAction onInvokeDestroy;

        public bool IsQuitting { get { return CommonUtil.IsQuitting; } }

        #region actionQueue
        private ConcurrentQueue<System.Action> actionQueue;

        public void EnqueueAction(System.Action action) {
            if (actionQueue == null) {
                actionQueue = new ConcurrentQueue<System.Action>();
            }
            actionQueue.Enqueue(action);
        }

        protected void TryInvokeSingleAction() {
            if (actionQueue != null) {
                if (actionQueue.TryDequeue(out System.Action action)) {
                    try {
                        action?.Invoke();
                    }
                    catch (System.Exception e) {
                        Debug.LogException(e);
                    }
                }
            }
        }

        protected void TryInvokeAllActions() {
            if (actionQueue != null) {
                while (actionQueue.TryDequeue(out System.Action action)) {
                    try {
                        action?.Invoke();
                    }
                    catch (System.Exception e) {
                        Debug.LogException(e);
                    }
                }
            }
        }

        public void Invoke(UnityAction action) {
            if (action != null) {
                action.Invoke();
            }
        }

        public void Invoke<T0>(UnityAction<T0> action, T0 arg0) {
            if (action != null) {
                action.Invoke(arg0);
            }
        }

        public void Invoke<T0, T1>(UnityAction<T0, T1> action, T0 arg0, T1 arg1) {
            if (action != null) {
                action.Invoke(arg0, arg1);
            }
        }

        public void Invoke<T0, T1, T2>(UnityAction<T0, T1, T2> action, T0 arg0, T1 arg1, T2 arg2) {
            if (action != null) {
                action.Invoke(arg0, arg1, arg2);
            }
        }
        #endregion

        #region CommonUtil
        public Transform GetTransform(string path) {
            return CommonUtil.GetTransform(transform, path);
        }

        public Transform GetTransform(Object parent, string path = null) {
            return CommonUtil.GetTransform(parent, path);
        }

        public GameObject GetGameObject(string path) {
            return CommonUtil.GetGameObject(transform, path);
        }

        public GameObject GetGameObject(Object parent, string path = null) {
            return CommonUtil.GetGameObject(parent, path);
        }

        public T GetComponent<T>(string path) where T : Component {
            return CommonUtil.GetComponent<T>(transform, path);
        }

        public T GetComponent<T>(Object parent, string path = null) where T : Component {
            return CommonUtil.GetComponent<T>(parent, path);
        }

        public GameObject Instantiate(string prefabPath, string path = null) {
            return CommonUtil.Instantiate(prefabPath, CommonUtil.GetTransform(transform, path));
        }

        public GameObject Instantiate(string prefabPath, Object parent, string path = null) {
            return CommonUtil.Instantiate(prefabPath, CommonUtil.GetTransform(parent, path));
        }

        public GameObject Instantiate(GameObject prefab, string path = null) {
            return CommonUtil.Instantiate(prefab, CommonUtil.GetTransform(transform, path));
        }

        public GameObject Instantiate(GameObject prefab, Object parent, string path = null) {
            return CommonUtil.Instantiate(prefab, CommonUtil.GetTransform(parent, path));
        }

        public T Instantiate<T>(string prefabPath, string path = null) where T : Component {
            return CommonUtil.Instantiate<T>(prefabPath, CommonUtil.GetTransform(transform, path));
        }

        public T Instantiate<T>(string prefabPath, Object parent, string path = null) where T : Component {
            return CommonUtil.Instantiate<T>(prefabPath, CommonUtil.GetTransform(parent, path));
        }

        public T Instantiate<T>(GameObject prefab, string path = null) where T : Component {
            return CommonUtil.Instantiate<T>(prefab, CommonUtil.GetTransform(transform, path));
        }

        public T Instantiate<T>(GameObject prefab, Object parent, string path = null) where T : Component {
            return CommonUtil.Instantiate<T>(prefab, CommonUtil.GetTransform(parent, path));
        }

        public virtual void Destroy() {
            //onInvokeDestroy?.Invoke();
            //BaseBehaviour[] behaviours = GetComponents<BaseBehaviour>();
            //foreach (BaseBehaviour behaviour in behaviours) {
            //    if (behaviour != this && behaviour.onInvokeDestroy != null) {
            //        behaviour.onInvokeDestroy.Invoke();
            //    }
            //}
            Destroy(gameObject);
        }

        public virtual void DestroyImmediate() {
            //onInvokeDestroy?.Invoke();
            DestroyImmediate(gameObject);
        }

        public void DestroyChild(string path) {
            CommonUtil.DestroyChild(transform, path);
        }

        public void DestroyChild(Object parent, string path = null) {
            CommonUtil.DestroyChild(parent, path);
        }

        public void DestroyChildImmediate(string path) {
            CommonUtil.DestroyChildImmediate(transform, path);
        }

        public void DestroyChildImmediate(Object parent, string path = null) {
            CommonUtil.DestroyChildImmediate(parent, path);
        }

        public void DestroyChildren(string path) {
            CommonUtil.DestroyChildren(transform, path);
        }

        public void DestroyChildren(Object parent, string path = null) {
            CommonUtil.DestroyChildren(parent, path);
        }

        public void DestroyChildrenImmediate(string path) {
            CommonUtil.DestroyChildrenImmediate(transform, path);
        }

        public void DestroyChildrenImmediate(Object parent, string path = null) {
            CommonUtil.DestroyChildrenImmediate(parent, path);
        }

        public void SetActive(string path, bool active) {
            CommonUtil.SetActive(transform, path, active);
        }

        public void SetActive(Object parent, string path, bool active) {
            CommonUtil.SetActive(parent, path, active);
        }

        public bool ToggleActive(string path) {
            return CommonUtil.ToggleActive(transform, path);
        }

        public bool ToggleActive(Object parent, string path = null) {
            return CommonUtil.ToggleActive(parent, path);
        }
        #endregion
    }

}
